/*
 * MIT License
 *
 * Copyright (c) 2024-2048 冰羽
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package cn.star.framework.rbac.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.star.framework.core.api.AppResult;
import cn.star.framework.entity.AbstractIdEntity;
import cn.star.framework.rbac.entity.Menu;
import cn.star.framework.rbac.entity.Resource;
import cn.star.framework.rbac.entity.Role;
import cn.star.framework.rbac.entity.User;
import cn.star.framework.rbac.service.AuthorizationService;
import cn.star.framework.rbac.service.RoleService;
import cn.star.framework.rbac.service.UserService;
import cn.star.framework.rbac.type.ResourceType;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 授权<br>
 *
 * @author zhaoweiping
 *     <p style='color: red'>Created on 2024-09-23 11:06:00
 * @since 3.0.0
 */
@Slf4j
@RestController
@RequestMapping(value = "/authorization")
@Api(tags = "授权管理")
public class AuthorizationController {
  @Autowired private UserService userService;
  @Autowired private RoleService roleService;
  @Autowired private AuthorizationService authorizationService;

  /**
   * 将角色列表授予用户
   *
   * @param id 用户Id{@link User#id}
   * @param roles 角色列表{@link Role}
   */
  @PostMapping(value = "/user-roles/{id}")
  @ApiOperation(value = "用户授权")
  public AppResult<?> setAuthorizationUserRoles(
      @PathVariable(value = "id") String id, @RequestBody(required = false) List<Role> roles) {
    User user = userService.findById(id);
    Assert.isFalse(user == null, "User cannot be empty");
    if (CollectionUtil.isNotEmpty(roles)) {
      // 检测角色是否存在，不存在则不能进行授权，无需抛出一场，只需过滤后打印日志，进行过滤后的角色列表进行授权
      Set<String> roleIds =
          roles.stream()
              .map(AbstractIdEntity::getId)
              .filter(StrUtil::isNotBlank)
              .collect(Collectors.toSet());
      List<Role> list = roleService.findAllByIds(roleIds);
      if (list.size() != roles.size()) {
        log.warn("角色列表参数中存在不在角色表中的非合法数据，已进行过滤处理，当前角色个数：{}，参数角色个数：{}", list.size(), roles.size());
      }
      roles = list;
    }
    authorizationService.setUserGroups(user, roles);

    return AppResult.ofSuccess();
  }

  /**
   * 将用户列表关联角色
   *
   * @param id 角色Id{@link Role#id}
   * @param users 用户列表{@link User}
   */
  @PostMapping(value = "/role-users/{id}")
  @ApiOperation(value = "用户授权(反向关联)")
  public AppResult<?> setAuthorizationRoleUsers(
      @PathVariable(value = "id") String id, @RequestBody(required = false) List<User> users) {
    Role role = roleService.findById(id);
    Assert.isFalse(role == null, "Role cannot be empty");
    if (CollectionUtil.isNotEmpty(users)) {
      Set<String> userIds =
          users.stream()
              .map(AbstractIdEntity::getId)
              .filter(StrUtil::isNotBlank)
              .collect(Collectors.toSet());
      List<User> list = userService.findAllByIds(userIds);
      if (list.size() != users.size()) {
        log.warn("用户列表参数中存在不在用户表中的非合法参数，已进行过滤处理，当前用户个数：{}，参数用户个数：{}", list.size(), users.size());
      }
      users = list;
    }
    authorizationService.setGroupUsers(role, users);

    return AppResult.ofSuccess();
  }

  /**
   * 将资源列表授予角色
   *
   * @param id 角色Id{@link Role#id}
   * @param resources 资源列表{@link Resource}
   */
  @SuppressWarnings({"rawtypes", "unchecked"})
  @PostMapping(value = "/role-resources/{id}")
  @ApiOperation(value = "资源授权")
  public AppResult<?> setAuthorizationRoleResources(
      @PathVariable(value = "id") String id,
      @RequestBody(required = false) List<Menu> resources) {
    Role role = roleService.findById(id);
    Assert.isFalse(role == null, "Role cannot be empty");
    if (CollectionUtil.isNotEmpty(resources)) {
      authorizationService.setGroupResources(role, resources);
    }

    return AppResult.ofSuccess();
  }

  /**
   * 将资源列表授予角色
   *
   * @param id 角色Id{@link Role#id}
   */
  @SuppressWarnings("rawtypes")
  @GetMapping(value = "/role-resources/{resourceType}/{id}")
  @ApiOperation(value = "资源授权")
  public AppResult<List<Resource>> getAuthorizationRoleResources(
      @PathVariable(value = "resourceType") ResourceType resourceType,
      @PathVariable(value = "id") String id) {
    Role role = roleService.findById(id);
    Assert.isFalse(role == null, "Role cannot be empty");
    List<Resource> list = authorizationService.getGroupAuthorizationResourceTrees(id, resourceType);

    return AppResult.ofSuccess(list);
  }
}
